﻿using EEM.LocalModels;
using EEM.Models;
using Modbus.Device;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace EEM.Helpers
{
    public class CommonHelper
    {
        public static EEMContext db = new EEMContext();

        //定时器
        public static System.Timers.Timer timer;
        //是否开启采集
        public static bool isStarted = true;
        //配置信息是否更新
        public static bool isSettingUpdates = false;
        //存储配置文件目录,Application.StartupPath:是项目启动可执行文件路径
        public static string filePath = Application.StartupPath + "/ConfigFiles";
        //通讯设置的文件路径
        public static string communicationPath = Path.Combine(filePath, "CommunicateSet.txt");
        //从站设置的文件路径
        public static string slavePath = Path.Combine(filePath, "slaveSet.json");
        //区域配置路径
        public static string areaPath = Path.Combine(filePath, "xArea.xml");
        //参数配置路径
        public static string paraPath = Path.Combine(filePath, "xPara.xml");

        //颜色状态
        public static string tempColorPath = Path.Combine(filePath, "tempStatusColor.json");
        public static string humColorPath = Path.Combine(filePath, "humStatusColor.json");

        //通信信息列表
        public static List<string> connectionList = new List<string>();
        //从站信息列表
        public static List<SlaveInfo> slaveList = new List<SlaveInfo>();
        //区域信息列表
        public static List<AreaInfo> areaList = new List<AreaInfo>();
        //参数信息列表
        public static List<ParamInfo> paraList = new List<ParamInfo>();

        //主站对象
        public static ModbusSerialMaster master = null;
        //串口
        public static SerialPort port = null;
        //串口打开标识
        public static bool isOpen = false;

        //实时数据集合
        public static Dictionary<int, AreaData> dicDatas = new Dictionary<int, AreaData>();

        public static void LoadConfigInfo()
        {
            //加载通讯配置信息
            LoadCommuniConfigInfo();
            //从站信息加载
            LoadSaveConfigInfo();
            //区域信息加载
            LoadAreaConfigInfo();
            //参数信息加载
            LoadParaConfigInfo();
        }

        //加载通讯配置信息
        public static void LoadCommuniConfigInfo()
        {
            string path = communicationPath;
            if (File.Exists(path))
            {
                var msgs = File.ReadAllText(communicationPath)?.Split(';').ToList();
                msgs.ForEach(
                    m => connectionList.Add(m.Split(':')[1])
                );
                CreateMaster();

               
            }
        }

        public static void CreateMaster()
        {
            //PortName: COM1; BaudRate: 9600; DataBit: 8; Parity: None; StopBit: 1
            if (port == null)
            {
                port = new SerialPort();
            }

            port.PortName = connectionList[0];
            port.BaudRate = connectionList[1].GetInt();
            port.DataBits = connectionList[2].GetInt();
            port.Parity = (Parity)Enum.Parse(typeof(Parity), connectionList[3]);
            port.StopBits = connectionList[4].Equals("1") ? StopBits.One : StopBits.Two;

            //if (port != null)
            //{
            try
            {
                port.Open();
                //if (port.IsOpen)
                //{
                isOpen = true;
                master = ModbusSerialMaster.CreateRtu(port);
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show("串口创建出错：" + ex.Message);
            }
            //}

        }

        public static void LoadSaveConfigInfo()
        {
            slaveList.Clear();
            if (File.Exists(slavePath))
            {
                string infoStr = File.ReadAllText(slavePath);
                slaveList = JsonConvert.DeserializeObject<List<SlaveInfo>>(infoStr);
            }
        }

        public static void LoadAreaConfigInfo()
        {
            areaList.Clear();
            if (File.Exists(areaPath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(areaPath);
                XmlElement? root = doc.DocumentElement;
                if (root != null)
                {
                    foreach (XmlNode node in root.ChildNodes)
                    {
                        int areaId = node.SelectSingleNode("AreaId").InnerText.GetInt();
                        string areaName = node.SelectSingleNode("AreaName").InnerText;
                        int slaveId = node.SelectSingleNode("SlaveId").InnerText.GetInt();
                        areaList.Add(
                            new AreaInfo()
                            {
                                AreaId = areaId,
                                AreaName = areaName,
                                SlaveId = slaveId
                            }
                        );
                    }
                }
            }
        }

        public static void LoadParaConfigInfo()
        {
            paraList.Clear();
            if (File.Exists(paraPath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(paraPath);
                if (doc != null)
                {
                    XmlElement? root = doc.DocumentElement;
                    foreach (XmlNode node in root.ChildNodes)
                    {
                        string paramName = node.SelectSingleNode("ParamName").InnerText;
                        int slaveId = node.SelectSingleNode("SlaveId").InnerText.GetInt();
                        int registerAddr = node.SelectSingleNode("RegisterAddr").InnerText.GetInt();
                        string dataTypes = node.SelectSingleNode("DataTypes").InnerText;
                        int digit = node.SelectSingleNode("Digit").InnerText.GetInt();
                        string paramDesc = node.SelectSingleNode("ParamDesc").InnerText;

                        paraList.Add(
                            new ParamInfo()
                            {
                                ParamName = paramName,
                                SlaveId = slaveId,
                                RegisterAddr = registerAddr,
                                DataTypes = dataTypes,
                                Digit = digit,
                                ParamDesc = paramDesc
                            }
                        );
                    }
                }
            }
        }


        #region 定时器

        public static void InitTimer()
        {
            timer = new System.Timers.Timer()
            {
                Interval = 2000,
                AutoReset = true,//是否持续执行
            };
            timer.Elapsed += Timer_Elapsed;//重复执行事件
            timer.Start();
        }
        public static void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            Task.Run(async () =>
            {
                //遍历从站列表
                //var master = CommonHelper.master;
                //var slaveList = CommonHelper.slaveList;
                //var areaList = CommonHelper.areaList;
                //var paraList = CommonHelper.paraList;
                //var dicDatas = CommonHelper.dicDatas;

                if (!port.IsOpen) return;

                foreach (SlaveInfo s in slaveList)
                {
                    byte slaveId = (byte)s.SlaveId;
                    ushort startAddr = (ushort)s.StartAddress;
                    ushort count = (ushort)s.Count;

                    ushort[] uDatas = null;

                    if (s.FunctionCode == 3)
                    {
                        uDatas = await master.ReadHoldingRegistersAsync(slaveId, startAddr, count);
                    }
                    else if (s.FunctionCode == 4)
                    {
                        uDatas = await master.ReadInputRegistersAsync(slaveId, startAddr, count);
                    }

                    //解析
                    if (uDatas.Length <= 0) return;
                    var paras = paraList.Where(p => (byte)p.SlaveId == slaveId).ToList();
                    decimal temperature = 0.0m;
                    int humidity = 0, co2 = 0;
                    foreach (ParamInfo par in paras)
                    {
                        ushort data = uDatas[par.RegisterAddr];

                        if (par.ParamName.Contains("Temper") && par.DataTypes.Equals("Float") && par.Digit > 0)
                        {
                            temperature = decimal.Parse(((double)data / Math.Pow(10, (double)par.Digit)).ToString($"F{par.Digit}"));
                        }
                        else if (par.ParamName.Contains("Humidity"))
                        {
                            humidity = (int)data;
                        }
                        else if (par.ParamName.Contains("CO2"))
                        {
                            co2 = (int)data;
                        }
                    }

                    AreaData areaData = new AreaData() { Temperature = temperature, Humidity = humidity, C02density = co2 };
                    AreaInfo areaInfo = areaList.Find(a => (byte)a.SlaveId == slaveId);
                    if (areaInfo != null)
                    {
                        int areaId = areaInfo.AreaId;
                        if (dicDatas.ContainsKey(areaId))
                        {
                            dicDatas[areaId] = areaData;
                        }
                        else
                        {
                            dicDatas.Add(areaId, areaData);
                        }
                    }
                }

                SaveOnDB(dicDatas);
            });
        }
        public static async void SaveOnDB(Dictionary<int, AreaData> dicDatas)
        {
            using (var trans = db.Database.BeginTransaction())
            {
                try
                {
                    foreach (int k in dicDatas.Keys)
                    {
                        AreaDatalnfo adi = db.AreaDatalnfos.SingleOrDefault(s => s.Areald == k);
                        AreaData areaData = dicDatas[k];

                        if (adi == null) //添加
                        {
                            db.AreaDatalnfos.Add(new AreaDatalnfo()
                            {
                                InsertTime = DateTime.Now,
                                Areald = k,
                                Temperature = areaData.Temperature,
                                Humidity = areaData.Humidity,
                                C02density = areaData.C02density
                            });
                        }
                        else //更新
                        {
                            adi.InsertTime = DateTime.Now;
                            adi.Temperature = areaData.Temperature;
                            adi.Humidity = areaData.Humidity;
                            adi.C02density = areaData.C02density;
                        }
                        await db.SaveChangesAsync();
                    }
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    MessageBox.Show("提交数据库出错：" + ex.Message);
                }
            }
        }
        #endregion
    }
}
